/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package Server;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
import Controller.Controller;
import java.rmi.*;
import java.rmi.server.*;
import java.util.ArrayList;
import Module.*;
import Shared.Callback;
import Shared.Server;
import java.io.IOException;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.Calendar;
import java.util.logging.Level;
import java.util.logging.Logger;
import sun.tools.tree.ThisExpression;

/**
 *
 * @author thorerikmidtb.
 * "UnicastRemoteObject is used for exporting a remote object with JRMP and obtaining a stub that communicates to the remote object".
 * From http://download.oracle.com/javase/1.5.0/docs/api/java/rmi/server/UnicastRemoteObject.html
 * Listens to RMI requests and implements the interface which is used by the client to invoke remote methods.
 *
 */
public class ServerImpl extends UnicastRemoteObject implements Server {

    Controller controller = new Controller();
    private static String ip = "";
    private ArrayList<Callback> userList = new ArrayList<Callback>();
    private ArrayList<String> ips = new ArrayList<String>();

    Mail mail = new Mail();

    /**
     * Empty constructor.
     * @throws RemoteException
     */
    public ServerImpl() throws RemoteException {
    }

    public static void getIp() {
        try {
            InetAddress addr = InetAddress.getLocalHost();
            ip += addr.getHostAddress();
            System.out.println("IP = " + ip);
        } catch (java.net.UnknownHostException ex) {
            Logger.getLogger(ServerImpl.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    /**
     * Method used to get the name of the server
     * @return
     */
    public static String getNaming() {
        return "ServerImpl";
    }
    /**
     * Method used to register a new project
     * @param name
     * @param description
     * @param goals
     * @param projectLeader
     * @returns prosjectID
     * @throws RemoteException
     */
    public synchronized int registerProject(String name, String description, String goals,String projectLeader) throws RemoteException {
        Project project = new Project(0, name, description, goals, projectLeader);
        return controller.getProject().registerProject(project);
    }
    /**
     * Method used to get a project from a projectID
     * @param id
     * @return
     * @throws RemoteException
     */
    public synchronized Module.Project getProject(int id)throws RemoteException{
        return controller.getProject().getProject(id);
    }
    /**
     * Method used to edit a project
     * @param id
     * @param name
     * @param description
     * @param goals
     * @param projectLeader
     * @throws RemoteException
     */
    public synchronized void editProject(int id, String name, String description, String goals,String projectLeader) throws RemoteException {
        controller.getProject().editProject(new Project(id, name, description, goals,projectLeader));
    }
    /**
     * Method used to delete a project
     * NOT IMPLEMENTED
     * @param id
     * @throws RemoteException
     */
    public synchronized void deleteProject(int id) throws RemoteException {
        Project project = new Project(id, "", "", "","");
        controller.getProject().deleteProject(project);
    }
    /**
     * Method used to get all the project
     * @return
     * @throws RemoteException
     */
    public ArrayList<Module.Project> getAllProjects() throws RemoteException {
        return controller.getProject().getProjects();
    }
    /**
     * Method used to get all project to a user
     * @param user
     * @return
     * @throws RemoteException
     */
    public ArrayList<Module.Project> getAllProjectsToUser(String user) throws RemoteException {
     return controller.getUser().getProjectForUser(controller.getUser().getUserForUsername(user));
    }
    /**
     * Method used to register a new activity
     * @param projectId
     * @param activityName
     * @param startDate
     * @param endDate
     * @param responsible
     * @param status
     * @param description
     * @param goals
     * @param location
     * @param onActionList
     * @throws RemoteException
     */
    public synchronized void registerActivity(int projectId, String activityName, String startDate, String endDate,
            String responsible, String status, String description, String goals, String location,
            boolean onActionList) throws RemoteException {

        Activity activity = new Activity(0, projectId, activityName, startDate, endDate, responsible, status,
                description, goals, location, onActionList);
        controller.getActivity().registerActivity(activity);
    }
    /**
     * Method used to edit a activity
     * @param id
     * @param projectId
     * @param activityName
     * @param startDate
     * @param endDate
     * @param responsible
     * @param status
     * @param description
     * @param goals
     * @param location
     * @param onActionList
     * @throws RemoteException
     */
    public synchronized void editActivity(int id, int projectId, String activityName, String startDate, String endDate,
            String responsible, String status, String description, String goals, String location,
            boolean onActionList) throws RemoteException {

        Activity activity = new Activity(id, projectId, activityName, startDate, endDate, responsible, status,
                description, goals, location, onActionList);
        controller.getActivity().editActivity(activity);
    }
    /**
     * Method used to delete an activity
     * @param id
     * @throws RemoteException
     */
    public synchronized void deleteActivity(int id) throws RemoteException {
        Activity activity = new Activity(id);
        controller.getActivity().deleteActivity(activity);
    }
    /**
     * Method used to get all activities to a project
     * @param projectId
     * @return
     */
    public ArrayList<Module.Activity> getAllActivities(int projectId) {
        Project p = new Project(projectId, "", "", "","");
        ArrayList<Module.Activity> activity = new ArrayList<Module.Activity>();
        activity = controller.getActivity().getActivitysToProject(p);
        return activity;
    }
    /**
     * Method used to
     * @param name
     * @param date
     * @param place
     * @param projectId
     * @param startTime
     * @param endTime
     * @param evaluation
     * @param preparation
     * @return
     * @throws RemoteException
     */
    public synchronized int registerSession(String name, String date, String place,int projectId,String startTime,
            String endTime, String evaluation, String preparation) throws RemoteException {
        Session session = new Session(0, projectId, name, date, place,startTime,endTime,evaluation,preparation);
        return controller.getSession().registerSession(session);
    }
    /**
     * Method used to register teamgoals and team delivery to a session
     * @param teamId
     * @param sessionId
     * @param teamGoal
     * @param teamDelivery
     */
    public void registerTeamSession(int teamId, int sessionId, String teamGoal, String teamDelivery){
        controller.getTeam().registerTeamSession(teamId, sessionId, teamGoal, teamDelivery);
    }
    /**
     * Method used to check if the user has inputed the correct info
     * @param username
     * @param password
     * @return
     * @throws RemoteException
     */
    public synchronized boolean loginn(String username, String password) throws RemoteException{
        boolean  b = controller.getUser().logInn(username, password);
        return b;
    }

    /**
     * Method used to edit a session
     * @param id
     * @param projectId
     * @param name
     * @param date
     * @param place
     * @param startTime
     * @param endTime
     * @param evaluation
     * @param preparation
     * @throws RemoteException
     */
    public synchronized void editSession(int id, int projectId, String name, String date, String place, String startTime
            ,String endTime, String evaluation, String preparation) throws RemoteException {
        Session session = new Session(id, projectId, name, date, place,startTime, endTime,evaluation,preparation);
        controller.getSession().editSession(session);
    }
    /**
     * Method used to delte session
     * @param id
     * @throws RemoteException
     */
    public synchronized void deleteSession(int id) throws RemoteException {
        Session s = new Session(id);
        controller.getSession().deleteSession(s);
    }
    /**
     * Method used to get the user to a username
     * @param username
     * @return
     * @throws RemoteException
     */
    public synchronized Module.User getUserForUsername(String username) throws RemoteException {
        return controller.getUser().getUserForUsername(username);
    }
    /**
     * method used to edit a decision
     * @param decisionList
     * @param projectId
     * @throws RemoteException
     */
    public void editDecisionList(ArrayList<DecisionList> decisionList, int projectId)throws RemoteException{
        controller.getDecisionlist().editDecisionList(decisionList,projectId);
    }
    /**
     * Method used to register a decisionlist
     * @param decisionList
     * @throws RemoteException
     */
    public void registerDecisionList(DecisionList decisionList)throws RemoteException{
        controller.getDecisionlist().registerDecisionList(decisionList);
    }
    /**
     * Method used to get all sessions to a project
     * @param id
     * @return
     * @throws RemoteException
     */
    public ArrayList<Module.Session> getAllSessionsToProject(int id) throws RemoteException {
        Project project = new Project(id, "", "", "","");
        return controller.getSession().getSessionsToProject(project);
    }
    /**
     * Method used to get the actionlist to a project
     * @param projectId
     * @return
     * @throws RemoteException
     */
    public ArrayList<ActionList> getActionListToProject(int projectId)throws RemoteException{
        return controller.getActionlist().getActionlist(projectId);
    }
    /**
     * Method used to get expert to a session
     * @param sessionId
     * @return
     * @throws RemoteException
     */
    public ArrayList<Module.User> getExpertsForSession(int sessionId) throws RemoteException{
        return controller.getSession().getExpertsToSession(sessionId);
    }
    /**
     * Method used to get all places a session can take place
     * @return
     * @throws RemoteException
     */
    public ArrayList<String> getAllPlaces()throws RemoteException{
        return controller.getResource().getAllSessionPlaces();
    }
    /**
     * Method used to get projectparticipants to a project
     * @param projectId
     * @return
     * @throws RemoteException
     */
    public ArrayList<Module.User> getProjectParticipants(int projectId) throws RemoteException{
        return controller.getProject().getUsersToProject(projectId);
    }
    /**
     * Method used to get all users
     * @return
     * @throws RemoteException
     */
    public ArrayList<Module.User> getAllUsers() throws RemoteException {
        return controller.getUser().getAllUsers();
    }
  /*
    public ArrayList<Module.User> getProjectLeader() throws RemoteException {
        return controller.getUser().getProjectLeaders();
    }

    public ArrayList<Module.User> getSecretaries() throws RemoteException {
        return controller.getUser().getSecretaries();
    }

    public ArrayList<Module.User> getFasilitator() throws RemoteException {
        return controller.getUser().getFasilitator();
    }
*/
    /**
     * Method used to edit the actionlist
     * @param liste
     * @throws RemoteException
     */
    public void editActionList(ArrayList<ActionList> liste)throws RemoteException{
        controller.getActionlist().editActionList(liste);
    }
    /**
     * Method used to register a user this method also sends out the email to the user
     * @param workplace
     * @param fullname
     * @param expertise
     * @param username
     * @return
     * @throws RemoteException
     */
    public synchronized Module.User registerUser(String workplace, String fullname,String expertise,String username) throws RemoteException {
        String password = getPassword(6);
        User user = new User(0, username,password,workplace,fullname,expertise);
        sendCredentialsToEmail(password, username, fullname);   //  <------------ Commenta ut sånn at me ikkje spamma kemsomhelst i testopprettingar!
        return controller.getUser().registerUser(user);
    }
    /**
     * Method userd to register a role to a user
     * @param userId
     * @param rolles
     * @throws RemoteException
     */
    public void registerRoleToUser(int userId, ArrayList<String> rolles)throws RemoteException{
        controller.getUser().registerRoleToUser(userId, rolles);
    }
    /**
     * method used to get roles to a user
     * @param userId
     * @return
     * @throws RemoteException
     */
    public ArrayList<String> getRoleToUser(int userId)throws RemoteException{
        return controller.getRole().getRoleToUser(userId);
    }

    /**
     * Method used to check if the username is saved
     * @param username
     * @return
     * @throws RemoteException
     */
    public boolean isUsernameRegistered(String username) throws RemoteException{
        return controller.getUser().isUsernameRegistered(username);
    }
    /**
     * Method used to register a team
     * @param name
     * @return
     * @throws RemoteException
     */
    public int registerTeam(String name)throws RemoteException{
        return controller.getTeam().registerTeam(new Team(0,name));
    }
    /**
     * Method used to edit a team
     * @param id
     * @param name
     * @throws RemoteException
     */
    public void editTeam(int id, String name)throws RemoteException{
        controller.getTeam().editTeam(new Team(id,name));
    }

    /**
     * Method used to get teams to a project
     * @param projectId
     * @return
     * @throws RemoteException
     */
    public ArrayList<Team> getTeamsToProject(int projectId)throws RemoteException{
        return controller.getTeam().getTeamsToProject(projectId);
    }
    /**
     * Method used to get team delivery and team goals to a session
     * @param sessionId
     * @return
     * @throws RemoteException
     */
    public ArrayList<Team> getTeamInfoToSession(int sessionId)throws RemoteException{
        return controller.getTeam().getTeamSession(sessionId);
    }
    /**
     * method used to get the users to a team
     * @param teamId
     * @return
     * @throws RemoteException
     */
    public ArrayList<User> getUsersToTeam(int teamId)throws RemoteException{
        return controller.getUser().getUsersToTeam(teamId);
    }
    /**
     * Method used to edit team goals and team delivery
     * @param teamId
     * @param sessionId
     * @param teamGoal
     * @param teamDelivery
     * @throws RemoteException
     */
    public void editTeamSession(int teamId, int sessionId, String teamGoal, String teamDelivery)throws RemoteException{
        controller.getTeam().editTeamSession(teamId, sessionId, teamGoal, teamDelivery);
    }


    /**
     * Method used to register users to a project
     * @param projectId
     * @param users
     * @param teamId
     * @param roleId
     * @throws RemoteException
     */
    public synchronized void registerUserToProject(int projectId, ArrayList<User> users,int teamId, int roleId) throws RemoteException{
        controller.getProject().setUsersToProject(users, projectId,teamId,roleId);
    }
    /**
     * Method used to delete users to project
     * @param projectid
     * @throws RemoteException
     */
    public void delteUsertoProject(int projectid) throws RemoteException{
        controller.getProject().deleteUserstoProject(new Project(projectid,"","","",""));
    }
    /**
     * Method used to register users to a session
     * @param sessionId
     * @param users
     * @param roleId
     * @param teamId
     * @throws RemoteException
     */
    public synchronized void registerUserToSession(int sessionId, ArrayList<User> users, int roleId, int teamId) throws RemoteException{
        controller.getSession().setUsersToSession(sessionId, users, roleId,teamId);
    }
    /**
     * method used to delete a tema
     * @param teamId
     * @throws RemoteException
     */
    public void deleteTeam(int teamId)throws RemoteException{
        controller.getTeam().deleteTeam(teamId);
    }
    /**
     * Method used to register a resorurce type
     * @param name
     * @return
     * @throws RemoteException
     */
    public int registerResourceType(String name)throws RemoteException{
        return controller.getResource().registerResourceType(name);
    }
    /**
     * Method used to register a new resoruce type
     * @param name
     * @param resourceTypeName
     * @param resourceTypeId
     * @return [0]= resourceID, [1]= resoruceTypeId
     * @throws RemoteException
     */
    public int[] registerResource(String name, String resourceTypeName, int resourceTypeId)throws RemoteException{
        return controller.getResource().registerResource(name,resourceTypeName, resourceTypeId);
    }
    /**
     * Method used to get all resoruce types
     * @return
     * @throws RemoteException
     */
    public ArrayList<ResourceType> getAllResourceType()throws RemoteException{
        return controller.getResource().getAllResourceType();
    }
    /**
     * Method sued to get all resrouces
     * @return
     * @throws RemoteException
     */
    public ArrayList<Resource> getAllResources() throws RemoteException{
        return controller.getResource().getAllResources();
    }
    /**
     * Method used to register resoruces to a project
     * @param resources
     * @return
     * @throws RemoteException
     */
    public String registerResourceToProject(ResourceProject resources)throws RemoteException{
        return controller.getResource().registerResourceToProject(resources);
    }
    /**
     * Method used to get resoruces to a project
     * @param projectId
     * @return
     * @throws RemoteException
     */
    public ArrayList<ResourceProject> getResourceToProject(int projectId)throws RemoteException{
        return controller.getResource().getResourcesToProject(projectId);
    }
    /**
     * Method used to delete resoruce to a project
     * @param projectId
     * @param resourceId
     * @throws RemoteException
     */
    public void deleteResourceToProject(int projectId, int resourceId)throws RemoteException{
        controller.getResource().deleteResourceToProject(projectId, resourceId);
    }
    /**
     * Method used to check if the username an password is correct
     * @param username
     * @param password
     * @return
     */
    public boolean isCorrectPassword(String username, String password){
        return controller.getUser().isCorrectPassword(username, password);
    }
    /**
     * Method sued to get users roles to a project
     * @param projectId
     * @param teamId
     * @return
     * @throws RemoteException
     */
    public ArrayList<addUserRoles> getUserRolesProject(int projectId, int teamId)throws RemoteException{
        return controller.getUser().getUserRolesProject(projectId,teamId);
    }
    /**
     * Method used to get users roles to a project
     * @param userId
     * @param projectId
     * @return
     * @throws RemoteException
     */
    public ArrayList<String> getRoleToUserProject(int userId, int projectId)throws RemoteException{
        return controller.getRole().getRoleToUserProject(userId, projectId);
    }
    /**
     * Method used to get users roles to a session
     * @param userId
     * @param sessionId
     * @return
     * @throws RemoteException
     */
    public ArrayList<String> getRoleToUserSession(int userId, int sessionId)throws RemoteException{
        return controller.getRole().getRoleToUserSession(userId, sessionId);
    }
    /**
     * Method used to get the decisionlist to a project
     * @param projectId
     * @return
     * @throws RemoteException
     */
    public ArrayList<DecisionList> getDecisionListToProject(int projectId)throws RemoteException{
        return controller.getDecisionlist().getDecisionListToProject(projectId);
    }
    /**
     * Method used to get all serssions to a user
     * @param userId
     * @return
     * @throws RemoteException
     */
    public ArrayList<Session> getAlleSessionsToUser(int userId)throws RemoteException{
        return controller.getSession().getAlleSessionsToUser(userId);
    }
    /**
     * Method used to remove users from a session
     * @param sessionId
     * @throws RemoteException
     */
    public synchronized void removeUsersFromSession(int sessionId) throws RemoteException{
        controller.getSession().deleteUsersFromSession(sessionId);
    }
    /**
     * Method used to set a user to the voicelist
     * @param projectId
     * @param userId
     * @return
     * @throws RemoteException
     */
    public boolean insertIntoVoiceList(int projectId, int userId)throws RemoteException{
        return controller.getVoiceList().insertIntoVoiceList(projectId, userId);
    }
    /**
     * Method used to remove a user from the voiceliste
     * @param projectId
     * @param userId
     * @throws RemoteException
     */
    public void removeFromVoiceList(int projectId, int userId)throws RemoteException{
        controller.getVoiceList().removeFromVoiceList(projectId, userId);
    }
    /**
     * Method used to get the decisionlist intro
     * @param projectId
     * @return
     * @throws RemoteException
     */
    public String getDecisionListIntro(int projectId)throws RemoteException{
        return controller.getDecisionlist().getDecisionListIntro(projectId);
    }
    /**
     * Method used to get the actionlist intro
     * @param projectId
     * @return
     * @throws RemoteException
     */
    public String getActionListIntro(int projectId)throws RemoteException{
        return controller.getActionlist().getActionListIntro(projectId);
    }
    /**
     * method used to edit the decisionlist intro
     * @param projectId
     * @param intro
     * @throws RemoteException
     */
    public void editDecionListIntro(int projectId, String intro)throws RemoteException{
        controller.getDecisionlist().setIntroduktion(projectId, intro);
    }
    /**
     * Method used to edit the actionlist intro
     * @param projectId
     * @param intro
     * @throws RemoteException
     */
    public void editActionListIntro(int projectId, String intro)throws RemoteException{
        controller.getActionlist().setIntroduktion(projectId, intro);
    }
    /**
     * method used to remove all users from the voicelist to a singel project
     * @param projectId
     * @throws RemoteException
     */
    public void removeVoiceList(int projectId)throws RemoteException{
        controller.getVoiceList().removeVoiceList(projectId);
    }
    /**
     * method used to edit a user
     * @param u
     * @throws RemoteException
     */
    public synchronized void editUser(User u) throws RemoteException {
        controller.getUser().editUser(u);
    }
    /**
     * method used to edit a user
     * @param u
     * @param fullname
     * @param expertise
     * @param workplace
     * @throws RemoteException
     */
    public synchronized void editUserInfo(User u, String fullname, String expertise, String workplace) throws RemoteException {
        controller.getUser().editUserInfo(new User(u.getId(), u.getUsername(), u.getPassword(), workplace, fullname, expertise));
    }
    /**
     * Method used to register a new chattlog
     * @param id
     * @param projectId
     * @param log
     * @throws RemoteException
     */
    public synchronized void registerChattLog(int id, int projectId, String log) throws RemoteException {
        ChattLog chattlog = new ChattLog(id, projectId, log);
        controller.getChattlog().registrerChattLog(chattlog);
    }
    /**
     * method used to get the chattlog to a project
     * @param projectId
     * @return
     * @throws RemoteException
     */
    public ArrayList<Module.ChattLog> getChattLogToProject(int projectId) throws RemoteException {
        Project project = new Project(projectId, "", "", "", "");
        if (controller.getChattlog().getChattLogToProject(project) != null) {
            return controller.getChattlog().getChattLogToProject(project);
        }
        ArrayList<Module.ChattLog> log = new ArrayList<Module.ChattLog>();
        return log;
    }
    /**
     * method used to edit a chattlog
     * @param chattlog
     * @throws RemoteException
     */
    public synchronized void editChattLog(Module.ChattLog chattlog) throws RemoteException {
        controller.getChattlog().editChattLog(chattlog);
    }
    /**
     * Method used to send out the text other users sends
     * @param message
     * @param c
     * @throws RemoteException
     */
    public synchronized void broadcast(String message, Callback c) throws RemoteException {
        checkCallbacks();
        if (!message.trim().isEmpty() && c.getSelectedProject() != null) {
            for (int i = 0; i < userList.size(); i++) {
                Callback user = userList.get(i);
                if (user.getSelectedProject().getId() == c.getSelectedProject().getId()) {
                    user.broadcastMessage(message, c.getUserName());
                }
            }
            ArrayList<ChattLog> log = getChattLogToProject(c.getSelectedProject().getId());

            if (log.isEmpty()) {
                controller.getChattlog().registrerChattLog(new ChattLog(0, c.getSelectedProject().getId(), "\n"+c.getUserName() + " wrote: "+message));
            } else if(message.length() + log.get(log.size()-1).getChattLog().length()>=7900){
                if(message.length()>=7900){
                    int size = message.length()/7900;
                    size+=1;
                    for(int i=0;i<size;i++){
                        String sub = message.substring(i*7900);
                        if(sub.trim().length()>0)controller.getChattlog().registrerChattLog(new ChattLog(0,c.getSelectedProject().getId(),"\n"+c.getUserName()+ " wrote: "+sub));
                        System.out.println("OVER 7900 ORD");
                    }
                }else{
                    Module.ChattLog newChatLog = new Module.ChattLog(0, c.getSelectedProject().getId(), "\n" + c.getUserName() +" wrote: " + message);
                    System.out.println("SUM OVER 7900!");
                    controller.getChattlog().registrerChattLog(newChatLog);
                }
                
            } 
            else {
                System.out.println("OKOKOKOK");
                System.out.println("mee " + message);
                Module.ChattLog newChatLog = new Module.ChattLog(log.get(log.size()-1).getId(), c.getSelectedProject().getId(), log.get(log.size()-1).getChattLog() + "\n" + c.getUserName() +" wrote: " + message);
                controller.getChattlog().editChattLog(newChatLog);
            }
           // getClientList(c);
        }
    }
    /**
     * Method used to connect to the servcer
     * @param c
     * @param ip
     * @throws RemoteException
     */
    public synchronized void connect(Callback c, String ip) throws RemoteException {
        userList.add(c);
        ips.add(ip);
    }
    /**
     * Method used to notify the other users if theres is a change to projects
     * @param c
     * @throws RemoteException
     */
    public synchronized void sendProjectUpdates(Callback c) throws RemoteException {
        checkCallbacks();
        if (!userList.isEmpty()) {
            for (Callback cb : userList) {
                if(!cb.getUserName().equals(c.getUserName()) && cb.getSelectedProject().getId() == c.getSelectedProject().getId()){
                    cb.cbUpdateProjectList();
                }
            }
        }
    }
    /**
     * method used to notify other users if thers a change on the decisionlist
     * @param c
     * @throws RemoteException
     */
    public synchronized void sendDecisionListUpdates(Callback c) throws RemoteException {
        checkCallbacks();
        if(!userList.isEmpty()) {
            for(Callback cb : userList) {
                cb.cbUpdateDecisionList();
            }

        }
    }
    /**
     * Method used to notify other users if thers a change on the actionList
     * @param c
     * @throws RemoteException
     */
    public synchronized void sendActionlistUpdates(Callback c) throws RemoteException {
        checkCallbacks();
        if(!userList.isEmpty()){
            for(Callback cb : userList){
                if(!cb.getUserName().equals(c.getUserName()) && cb.getSelectedProject().getId() == c.getSelectedProject().getId()){
                    cb.cbUpdateActionlist();

                }
             }
        }
    }
    /**
     * Method used to notify other users if thers a change on one off the activities
     * @param c
     * @throws RemoteException
     */
    public synchronized void sendActivityUpdates(Callback c) throws RemoteException {
        checkCallbacks();
        if(!userList.isEmpty()){
            for(Callback cb : userList){
                if(!cb.getUserName().equals(c.getUserName()) && cb.getSelectedProject().getId() == c.getSelectedProject().getId()){
                     cb.cbUpdateActivityList();
                }
            }
        }
    }
    /**
     * method used to notify other users if theres a change on one off the resoruces
     * @param c
     * @throws RemoteException
     */
    public synchronized void sendResourceUpdates(Callback c) throws RemoteException {
        checkCallbacks();
        if(!userList.isEmpty()){
            for(Callback cb : userList){
                if(!cb.getUserName().equals(c.getUserName()) && cb.getSelectedProject().getId() == c.getSelectedProject().getId()){
                    cb.cbUpdateResources();
                }
            }
        }
    }
    /**
     * Method used to notify others users if thers a change to users
     * @param c
     * @throws RemoteException
     */
    public synchronized void sendUserListUpdates(Callback c) throws RemoteException {
        checkCallbacks();
        if(!userList.isEmpty()){
            for(Callback cb : userList){
                if(!cb.getUserName().equals(c.getUserName()) && cb.getSelectedProject().getId() == c.getSelectedProject().getId()){
                    cb.cbUpdateUserList();
               }
            }
        }
    }
    /**
     * Method used to notify other users if thers a change to the voicelist
     * @param c
     * @throws RemoteException
     */
    public synchronized void sendVoiceListUpdates(Callback c) throws RemoteException {
        checkCallbacks();
        if(!userList.isEmpty()){
            for(Callback cb : userList){
                if(!cb.getUserName().equals(c.getUserName()) && cb.getSelectedProject().getId() == c.getSelectedProject().getId()){

                cb.cbUpdateVoiceList();
                }
            }
        }
    }
    /**
     * method used to get the users on the voicelist
     * @param projectId
     * @return
     * @throws RemoteException
     */
    public ArrayList<User> getVoiceListUsers(int projectId) throws RemoteException {

        return controller.getVoiceList().getUsersAddedToVoiceList(projectId);

    }
    /**
     * method used to notify other users that there is a countdown in progress
     * @param c
     * @param min
     * @throws RemoteException
     */
    public void sendCountDownStarts(Callback c, int min) throws RemoteException {
        checkCallbacks();
        if(!userList.isEmpty()){
            for(Callback cb : userList){
                if(!cb.getUserName().equals(c.getUserName()) && cb.getSelectedProject().getId() == c.getSelectedProject().getId()){
                cb.cbStartCountDown(min);
            }
          }
        }
    }
    /**
     * Method to notify other users that the countdown is stopped
     * @param c
     * @throws RemoteException
     */
    public void sendCountDownStops(Callback c) throws RemoteException {
        checkCallbacks();
        if(!userList.isEmpty()){
            for(Callback cb : userList){
                if(!cb.getUserName().equals(c.getUserName()) && cb.getSelectedProject().getId() == c.getSelectedProject().getId()){
                cb.cbStopCountDown();
            }
          }
        }
    }
    /**
     * method used to notfy other users that the countdown in startet
     * @param c
     * @throws RemoteException
     */
    public void sendCountDownResumes(Callback c) throws RemoteException {
        checkCallbacks();
        if(!userList.isEmpty()){
            for(Callback cb : userList){
                if(!cb.getUserName().equals(c.getUserName()) && cb.getSelectedProject().getId() == c.getSelectedProject().getId()){
                cb.cbResumeCountDown();
            }
          }
        }
    }
    /**
     * method used to notify other users that there is a change to the sessions
     * @param c
     * @throws RemoteException
     */
    public synchronized void sendSessionUpdates(Callback c) throws RemoteException {
        checkCallbacks();
        if(!userList.isEmpty()){
            for(Callback cb : userList){
                if(!cb.getUserName().equals(c.getUserName()) && cb.getSelectedProject().getId() == c.getSelectedProject().getId()){
                cb.cbUpdateSessions();
                }
        }
    }
        }

        /**
         * method used to conenct to the chat
         * @param c
         * @param ip
         * @throws RemoteException
         */
    public synchronized void connectChat(Callback c, String ip) throws RemoteException {
        if(c.getSelectedProject()!=null){
            userList.add(c);
            ips.add(ip);
            for(int i=0;i<userList.size();i++){
                Callback user =userList.get(i);
                if(user.getSelectedProject().getId() == c.getSelectedProject().getId()){
                    getClientList(user);
                    user.connectMessage(c.getUserName());
                }
            }
        }
       // getClientList(c);
    }
    /**
     * method used to quit the program
     * @param c
     * @param ip
     * @throws RemoteException
     */
    public synchronized void quit(Callback c,String ip) throws RemoteException {
        if(c.getSelectedProject()!=null){
        userList.remove(c);
        for(int i=0;i<ips.size();i++){
            if(ips.get(i).equals(ip)) ips.remove(i);
        }
        for (int i = 0; i < userList.size(); i++) {
            Callback user = userList.get(i);
            if (c.getSelectedProject().getId() == user.getSelectedProject().getId()) {
                user.quitMessage(c.getUserName());
                getClientList(user);
                    }
                }
        getClientList(c);
    }
    }
    /**
     * method used to get all the clients on a project
     * @param c
     * @throws RemoteException
     */
    public synchronized void getClientList(Callback c) throws RemoteException {
        checkCallbacks();
        if (c.getSelectedProject() != null) {
            ArrayList<String> newList = new ArrayList<String>();
            for (int g = 0; g < userList.size(); g++) {
                Callback user = userList.get(g);
                if (user.getSelectedProject().getId() == c.getSelectedProject().getId()) {
                    newList.add(user.getUserName());
                    for (int i = 0; i < userList.size(); i++) {
                        Callback newUser = userList.get(i);
                        if (newUser.getSelectedProject().getId() == c.getSelectedProject().getId()) {
                            userList.get(i).getClientList(newList);
                }
            }
                        }
                    }
        }
    }
    /**
     * Method used to send email to the new user
     * @param clientPassword
     * @param clientUsername
     * @param fullName
     * @throws RemoteException
     */
    public synchronized void sendCredentialsToEmail(String clientPassword, String clientUsername, String fullName) throws RemoteException {
        mail.setClientPassword(clientPassword);
        mail.setClientUsername(clientUsername);
        mail.setEmailTo(clientUsername);
        mail.setSubject("Registering av ny bruker fullført");
        mail.setWelcomeText("Hei " + fullName +"!\nDu har akkurat blitt registert som ny bruker i forbindelse med Høgskolen i Sør-Trøndelag sitt system for Concurrent Design. "
                + "\nDu kan når som helst endre passordet i programmet under endre bruker.");
        mail.setEndText("Hvis du ikke er vedkommende, vennligst se bort fra denne eposten."
                + "\nMed vennlig hilsen,"
                + "\n\nHøgskolen i Sør-Trøndelag");
        mail.sendMail();
    }

    /**
     * method used to check if all the clients still is conected
     * @throws RemoteException
     */
    public void checkCallbacks() throws RemoteException {
        for (int i = 0; i < userList.size(); i++) {
            try {
                InetAddress address = InetAddress.getByName(ips.get(i));
                if(!address.isReachable(100)){
                    quit(userList.get(i),ips.get(i));
                    ips.remove(i);
                  }
            } catch (java.net.UnknownHostException ex) {
                Logger.getLogger(ServerImpl.class.getName()).log(Level.SEVERE, null, ex);
            }catch (IOException e){
                    System.err.println("Unable to reach " + e);
           }  

                
        }
    }
   /**
    * Method used to start the server
    * @param args
    * @throws Exception
    */
    public static void main(String[] args) throws Exception {
        System.setProperty("java.rmi.dgc.leaseValue","2000");
        getIp();
        System.out.println("This is the naming: "+ getNaming());
        System.setProperty("java.rmi.server.hostname", ip);
        try {
            LocateRegistry.createRegistry(1099);
            Server server = new ServerImpl();
            Tray tray = new Tray(server);

            Naming.rebind("ServerImpl", server);
            //  } catch (MalformedURLException mal) {
        //    System.out.println("UH OH! We got an error here(1): " + mal);
        } catch (RemoteException re) {
            System.out.println("UH OH! We got an error here(2): " + re);
        } catch (Exception e) {
            System.out.println("UH OH! We got an error here(4): " + e);
        }
    }
    /**
     * Private method used to autogenerate a password
     * @param n
     * @return
     */
    private String getPassword(int n) {
        char[] pw = new char[n];
        int c = 'A';
        int r1 = 0;
        for (int i = 0; i < n; i++) {
            r1 = (int) (Math.random() * 2);
            switch (r1) {
                case 0:
                    c = '0' + (int) (Math.random() * 10);
                    break;
                case 1:
                    c = 'a' + (int) (Math.random() * 26);
                    break;
            }
            pw[i] = (char) c;
        }
        return new String(pw);
    }
}
